/**
 * Urban Parks
 *
 * Team M&M's:
 * Michael Satran Jr
 * Michael Pogson
 * Stephen Hunter
 *
 * Date: Mar 1, 2012
 */
package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import controller.Controller;
import model.Date;
import model.Job;


/**
 * This is a JPanel which displays a Calendar with the given jobs, month, and year.
 * 
 * @author Michael Satran Jr
 */
@SuppressWarnings("serial")
public class CalendarPanel extends JPanel {
	
	/**
	 * This is the frame which this JPanel is contained.
	 * This reference exists in order to use the pack() method when setPreferredSize() is used
	 * for this JPanel.
	 */
	private JFrame my_frame;
	
	/**
	 * This is an array of JPanels for each day in a month. This array is constantly
	 * being recreated based on the month this calendar is currently displaying
	 * because the amount of days varies for each month.
	 */
	private JPanel[] my_day_panels;
	
	/**
	 * This is a map which contains the jobs for each start date.
	 * We are using a List<Job> for collision detection purposes. Also, several jobs have the same start dates. 
	 */
	private Map<Date, List<Job>> my_jobs;
	
	/**
	 * This is an integer that spans between 1 and 12 it is the current month the calendar is showing.
	 */
	private int my_month;
	/**
	 * This is an integer which contains the current year the calendar is showing.
	 */
	private int my_year;
	/**
	 * This is a reference to the controller in order to pass into the VolunteerInfoPanel which gives it the option
	 * to blackball a volunteer.
	 */
	private Controller my_controller;
	
	/**
	 * This is a label which shows the name of the month being shown.
	 */
	private JLabel my_month_label;
	
	/**
	 * This is the button which gets the month before that which is being shown.
	 */
	private JButton my_prev_button = new JButton("<<");
	
	/**
	 * This is the button which gets the month after that which is being shown.
	 */
	private JButton my_next_button = new JButton(">>");
	
	/**
	 * This is the JPanel which holds the days_panels.
	 */
	private JPanel my_days_container;
	
	/**
	 * Constructs a new CalendarPanel.
	 * 
	 * @param the_jobs The jobs which are to be shown on the calendar.
	 * @param the_month The month which is to be shown first on the calendar.
	 * @param the_year The year which is to be shown first on the calendar.
	 * @param the_frame The frame which will hold this calenda.r
	 * @param the_controller A reference to the controller.
	 */
	public CalendarPanel(List<Job> the_jobs, int the_month, int the_year, JFrame the_frame, Controller the_controller) {
		super();
		my_days_container = new JPanel();
		my_month = the_month;
		my_year = the_year;
		my_controller = the_controller;
		my_month_label = new JLabel();
		
		if (the_frame == null) {
			my_frame = new JFrame();
		} else {
			my_frame = the_frame;
		}
		
		
		my_jobs = new HashMap<Date, List<Job>>(the_jobs.size());
		for (Job offset : the_jobs) {
			addJobToMap(offset);
		}
	}
	
	/**
	 * Adds a job to the jobs map.
	 * @param the_job The job to add to the map.
	 */
	private void addJobToMap(Job the_job) {
		if (my_jobs.containsKey(the_job.getStartDate())) {
			my_jobs.get(the_job.getStartDate()).add(the_job);
		} else {
			List<Job> temp = new LinkedList<Job>();
			temp.add(the_job);
			my_jobs.put(the_job.getStartDate(), temp);
		}
	}
	
	/**
	 * Updates the calendar based on the new jobs given and the new month and year.
	 * @param the_jobs The jobs to update the calendar with.
	 * @param the_month The month which is to be shown.
	 * @param the_year The year which is to be shown.
	 */
	public void update(List<Job> the_jobs, int the_month, int the_year) {
		if (the_jobs != null) {
			for (Job offset : the_jobs) {
				addJobToMap(offset);
			}
		}
		
		my_month = the_month;
		my_year = the_year;
		
		my_month_label.setText(Date.getMonthName(my_month) + ", " + my_year);
		my_month_label.setFont(new Font("Arial", Font.PLAIN, 35));
		
		/**
		 * Add week day names at the top of calendar.
		 */
		Date temp = new Date(my_month, 1, my_year);
		int dayOfWeek = temp.getDayOfWeek();

		my_day_panels = new JPanel[Date.daysInMonth(my_month, my_year) + dayOfWeek];
		my_days_container.removeAll();
		//Add blank spaces so the days match up to the week day.
		int last_days_of_previous_month = Date.daysInMonth(my_month - 1 % 12, my_year);
		int previous_month_days = last_days_of_previous_month - dayOfWeek + 1;
		for (int i = 0; i < dayOfWeek; i++) {
			JLabel dayLabel = new JLabel(Integer.toString(previous_month_days+i));
			dayLabel.setForeground(Color.GRAY);
			my_day_panels[i] = new JPanel();
			my_day_panels[i].setBorder(BorderFactory.createLineBorder(Color.black));
			my_day_panels[i].setLayout(new BorderLayout());
			my_day_panels[i].add(dayLabel, BorderLayout.NORTH);
			my_day_panels[i].setVisible(true);
			my_days_container.add(my_day_panels[i]);
		}
		
		for (int i = dayOfWeek; i < my_day_panels.length; i++) {
			JLabel dayLabel = new JLabel(Integer.toString(i-dayOfWeek+1));
			my_day_panels[i] = new JPanel();
			my_day_panels[i].setLayout(new BorderLayout());
			my_day_panels[i].add(dayLabel, BorderLayout.NORTH);
			my_day_panels[i].setBorder(BorderFactory.createLineBorder(Color.black));
			my_day_panels[i].setBackground(Color.WHITE);
			
			List<Job> jobsForDay = my_jobs.get(new Date(my_month, i - dayOfWeek + 1, my_year));
			if (jobsForDay != null) {
				JList jobsList = new JList(jobsForDay.toArray());
				jobsList.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent e) {
						Job job = (Job)((JList) e.getComponent()).getSelectedValue();
						JobInformationPanel panel = new JobInformationPanel(job, my_controller);
						panel.setup();
						JFrame frame = new JFrame("Job Information");
						frame.setContentPane(panel);
						frame.pack();
						frame.setVisible(true);
					}
				});
				my_day_panels[i].add(new JScrollPane(jobsList), BorderLayout.CENTER);
			}
			
			my_day_panels[i].setVisible(true);
			my_days_container.add(my_day_panels[i]);
		}
		int lines = my_day_panels.length / 7;
		
		if (my_day_panels.length % 7 > 0) {
			lines++;
		}
		
		this.setPreferredSize(new Dimension(7 * 115,  lines * 115));
		my_frame.pack();
		my_frame.repaint();
	}
	
	/**
	 * Sets this CalendarPanel up. Adds all Components to the Panel, attaches listeners, etc.
	 */
	public void setup() {
		this.setLayout(new BorderLayout(20, 5));
		
		JPanel northRegion = new JPanel(new BorderLayout());
		
		JPanel month_label_container = new JPanel(new FlowLayout(FlowLayout.CENTER));
		month_label_container.add(my_month_label);
		
		JPanel buttons_container = new JPanel();
		buttons_container.setLayout(new BorderLayout());
		
		buttons_container.add(month_label_container, BorderLayout.NORTH);
		buttons_container.add(my_next_button, BorderLayout.EAST);
		buttons_container.add(my_prev_button, BorderLayout.WEST);
		
		/**
		 * Add week day names at the top of calendar.
		 */
		JPanel week_names = new JPanel(new GridLayout(0, 7));
		String[] daysOfWeeks = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
		for (int i = 0; i < 7; i++) {
			week_names.add(new JLabel(daysOfWeeks[i]));
		}
		
		buttons_container.add(week_names, BorderLayout.SOUTH);
		
		northRegion.add(buttons_container);
		
		my_prev_button.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				my_month--;
				if (my_month == 0) {
					my_year--;
					my_month = 12;
				}
				update(null, my_month, my_year);
			}
			
		});
		
		my_next_button.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				my_month++;
				if (my_month == 13) {
					my_year++;
					my_month = 1;
				}
				update(null, my_month, my_year);
			}
			
		});
		
		my_days_container.setLayout(new GridLayout(0, 7, 4, 4));
		
		update(null, my_month, my_year);
		
		this.add(northRegion, BorderLayout.NORTH);
		this.add(my_days_container, BorderLayout.CENTER);
	}
}
